package config

import (
	"encoding/json"
	"log"
	"os"
	"strings"

	"github.com/fsnotify/fsnotify"
	"github.com/spf13/viper"
)

var Client_Token string
var WS_ADDR string
var BLE_NAME_FILTER string
var CONN_LIMIT int
var DETAIL_LOG bool
var BASE64_ON bool

const token_key = "token"
const ws_addr_key = "ws_addr"
const ble_name_key = "ble_name"
const max_conn_key = "ble_max_conn"
const detail_log_key = "detail_log"
const base64_key = "base64"

const token_default = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJtQ3ViZSIsInN1YiI6Im1DdWJlIiwiYXVkIjoicmFzcDQiLCJpYXQiOjE2MjkzNTQ3Mzl9.hcw7sgukAXkmb8bLAp0gMntcgjfM-5voXkvQpRAwuC4"
const ws_addr_default = "wss://test.izar.animalmonitor.online/"
const ble_name_default = "M_IZAR_TEST"
const max_conn_default = 4
const detail_log_default = 0
const base64_default = 1

const ap_ssid_template = "m_gw_%s"
const ap_pass_template = "movellaiam"

func Get(callback func()) {
	viper.SetDefault(token_key, token_default)
	viper.SetDefault(ws_addr_key, ws_addr_default)
	viper.SetDefault(ble_name_key, ble_name_default)
	viper.SetDefault(max_conn_key, max_conn_default)
	viper.SetDefault(detail_log_key, detail_log_default)
	viper.SetDefault(base64_key, base64_default)
	viper.SetConfigFile("./config.json")
	viper.AddConfigPath(".") // Determine multiple config path
	viper.SetConfigType("json")
	err := viper.ReadInConfig()
	if err != nil {
		log.Printf("Fatal error to read config file: %s\r\n", err)
		log.Printf("Reset config.json\r\n")
		Reset()
	}

	Client_Token = viper.GetString(token_key)
	WS_ADDR = viper.GetString(ws_addr_key)
	BLE_NAME_FILTER = viper.GetString(ble_name_key)
	CONN_LIMIT = viper.GetInt(max_conn_key)
	log.Printf("[Config] BLE name:%s\r\n", BLE_NAME_FILTER)
	log.Printf("[Config] WS Addr:%s\r\n", WS_ADDR)
	log.Printf("[Config] Client Token:%s\r\n", Client_Token)
	log.Printf("[Config] BLE Max Connection:%d\r\n", CONN_LIMIT)
	viper.WatchConfig()

	viper.OnConfigChange(func(e fsnotify.Event) {
		log.Printf("[Config] file changed:%s\r\n", e.Name)
		Client_Token = viper.GetString(token_key)
		WS_ADDR = viper.GetString(ws_addr_key)
		BLE_NAME_FILTER = viper.GetString(ble_name_key)
		CONN_LIMIT = viper.GetInt(max_conn_key)
		if viper.GetInt(detail_log_key) == 1 {
			DETAIL_LOG = true
		} else {
			DETAIL_LOG = false
		}
		if viper.GetInt(base64_key) == 1 {
			BASE64_ON = true
		} else {
			BASE64_ON = false
		}

		log.Printf("[Config] BLE name:%s\r\n", BLE_NAME_FILTER)
		log.Printf("[Config] WS Addr:%s\r\n", WS_ADDR)
		log.Printf("[Config] Client Token:%s\r\n", Client_Token)
		log.Printf("[Config] BLE Max Connection:%d\r\n", CONN_LIMIT)
		log.Printf("[Config] Detail log enabled:%v\r\n", DETAIL_LOG)
		log.Printf("[Config] Base64 enabled:%v\r\n", BASE64_ON)
		callback()
	})
}
func Reset() error {
	config := make(map[string]interface{})
	config[token_key] = token_default
	config[ws_addr_key] = ws_addr_default
	config[ble_name_key] = ble_name_default
	config[max_conn_key] = max_conn_default
	config[detail_log_key] = detail_log_default
	config[base64_key] = base64_default
	str, _ := json.Marshal(config)
	log.Printf("[Config] config json : %s\r\n", string(str))
	err := os.WriteFile("./config.json", str, 0644)
	if err != nil {
		log.Printf("[Config] Failed to write config.json, err: %v\r\n", err)
		return err
	}
	return nil
}
func GetAP_SSID_Template() string {
	return ap_pass_template
}
func GetAP_PASS_Template() string {
	return ap_pass_template
}
func GetHostapd() (ssid string, pass string, err error) {
	hostapd_config, err := os.ReadFile("/etc/hostapd/hostapd.conf")
	if err != nil {
		log.Printf("[getHostapd_config] Read hostapd.conf failed\r\n")
		return "", "", err
	}
	apd_conf := string(hostapd_config)
	ssid_index := strings.Index(apd_conf, "ssid=")
	pass_index := strings.Index(apd_conf, "wpa_passphrase=")
	ssid = apd_conf[ssid_index+len("ssid="):]
	pass = apd_conf[pass_index+len("wpa_passphrase="):]
	ssid = ssid[0:strings.Index(ssid, "\n")]
	pass = pass[0:strings.Index(pass, "\n")]
	return ssid, pass, nil
}
func SetHostapd(ssid string, pass string) {
	old_ssid, old_pass, _ := GetHostapd()
	hostapd_config, err := os.ReadFile("/etc/hostapd/hostapd.conf")
	if err != nil {
		log.Printf("[setHostapd_config] Read hostapd.conf failed\r\n")
	}
	apd_conf := string(hostapd_config)
	apd_conf = strings.Replace(apd_conf, old_ssid, ssid, -1)
	apd_conf = strings.Replace(apd_conf, old_pass, pass, -1)
	err = os.WriteFile("/etc/hostapd/hostapd.conf", []byte(apd_conf), 0644)
	if err != nil {
		log.Printf("[setHostapd_config] Write hostapd.conf failed\r\n")
	}
}
